﻿// MemPtr, IntPtr alternative with utility.
// C# version.

// Copyright (C) 2014 Nathan Moschkin.

using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;

namespace DataTools.Memory
{
    /// <summary>
    /// MemPtr interop pointer structure.
    /// </summary>
    public struct MemPtr
    {
        private unsafe void* _ptr;

        /// <summary>
        /// Returns INVALID_HANDLE_VALUE (-1)
        /// </summary>
        public static readonly MemPtr InvalidHandle = new MemPtr((IntPtr)(int)-1);

        /// <summary>
        /// Returns a null pointer.
        /// </summary>
        public static readonly MemPtr Empty = new MemPtr((IntPtr)0);

        /// <summary>
        /// Returns the handle to the memory buffer.
        /// </summary>
        public IntPtr Handle
        {
            get
            {
                unsafe
                {
                    return (IntPtr)_ptr;
                }
            }
            set
            {
                unsafe
                {
                    _ptr = value.ToPointer();
                }
            }
        }

        /// <summary>
        /// Returns the pointer to the memory buffer.
        /// </summary>
        /// <returns></returns>
        public unsafe void* ToPointer()
        {
            return _ptr;
        }

        /// <summary>
        /// Returns a 32 bit integer that represents the pointer in memory.
        /// </summary>
        /// <returns></returns>
        public int ToInt32()
        {
            unsafe
            {
                return (int)((ulong)(_ptr) & 0xffffffff);
            }
        }

        /// <summary>
        /// Returns a 64 bit integer that represents the pointer in memory.
        /// </summary>
        /// <returns></returns>
        public long ToInt64()
        {
            unsafe
            {
                return (long)_ptr;
            }
        }

        #region Indexers

        /// <summary>
        /// Sets the byte at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to start copying.</param>
        /// <param name="value">Value to set.</param>
        /// <returns></returns>
        public void byteAt(long index, byte value)
        {
            unsafe
            {
                *(byte*)(((long)_ptr) + index) = value;
            }
        }

        /// <summary>
        /// Returns the byte at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to start copying.</param>
        /// <returns></returns>
        public byte byteAt(long index)
        {
            unsafe
            {
                return *(byte*)(((long)_ptr) + index);
            }
        }

        /// <summary>
        /// Sets the signed byte at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to start copying.</param>
        /// <param name="value">Value to set.</param>
        /// <returns></returns>
        public void sbyteAt(long index, sbyte value)
        {
            unsafe
            {
                *(sbyte*)(((long)_ptr) + index) = value;
            }
        }

        /// <summary>
        /// Returns the signed byte at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to start copying.</param>
        /// <returns></returns>
        public sbyte sbyteAt(long index)
        {
            unsafe
            {
                return *(sbyte*)(((long)_ptr) + index);
            }
        }

        /// <summary>
        /// Sets the character at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to start copying.</param>
        /// <param name="value">Value to set.</param>
        /// <returns></returns>
        public void charAt(long index, char value)
        {
            unsafe
            {
                *(char*)(((long)_ptr) + index) = value;
            }
        }

        /// <summary>
        /// Returns the character at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to start copying.</param>
        /// <returns></returns>
        public char charAt(long index)
        {
            unsafe
            {
                return *(char*)(((long)_ptr) + index);
            }
        }

        /// <summary>
        /// Sets the Int16 at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to start copying.</param>
        /// <param name="value">Value to set.</param>
        /// <returns></returns>
        public void shortAt(long index, short value)
        {
            unsafe
            {
                *(short*)(((long)_ptr) + index) = value;
            }
        }

        /// <summary>
        /// Returns the Int16 at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to start copying.</param>
        /// <returns></returns>
        public short shortAt(long index)
        {
            unsafe
            {
                return *(short*)(((long)_ptr) + index);
            }
        }

        /// <summary>
        /// Sets the UInt16 at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to start copying.</param>
        /// <param name="value">Value to set.</param>
        /// <returns></returns>
        public void ushortAt(long index, ushort value)
        {
            unsafe
            {
                *(ushort*)(((long)_ptr) + index) = value;
            }
        }

        /// <summary>
        /// Returns the UInt16 at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to start copying.</param>
        /// <returns></returns>
        public ushort ushortAt(long index)
        {
            unsafe
            {
                return *(ushort*)(((long)_ptr) + index);
            }
        }

        /// <summary>
        /// Sets the Int32 at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to start copying.</param>
        /// <param name="value">Value to set.</param>
        /// <returns></returns>
        public void intAt(long index, int value)
        {
            unsafe
            {
                *(int*)(((long)_ptr) + index) = value;
            }
        }

        /// <summary>
        /// Returns the Int32 at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to start copying.</param>
        /// <returns></returns>
        public int intAt(long index)
        {
            unsafe
            {
                return *(int*)(((long)_ptr) + index);
            }
        }

        /// <summary>
        /// Sets the UInt32 at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to start copying.</param>
        /// <param name="value">Value to set.</param>
        /// <returns></returns>
        public void uintAt(long index, uint value)
        {
            unsafe
            {
                *(uint*)(((long)_ptr) + index) = value;
            }
        }

        /// <summary>
        /// Returns the UInt32 at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to start copying.</param>
        /// <returns></returns>
        public uint uintAt(long index)
        {
            unsafe
            {
                return *(uint*)(((long)_ptr) + index);
            }
        }

        /// <summary>
        /// Sets the Int64 at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to start copying.</param>
        /// <param name="value">Value to set.</param>
        /// <returns></returns>
        public void longAt(long index, long value)
        {
            unsafe
            {
                *(long*)(((long)_ptr) + index) = value;
            }
        }

        /// <summary>
        /// Returns the Int64 at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to start copying.</param>
        /// <returns></returns>
        public long longAt(long index)
        {
            unsafe
            {
                return *(long*)(((long)_ptr) + index);
            }
        }

        /// <summary>
        /// Sets the UInt64 at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to start copying.</param>
        /// <param name="value">Value to set.</param>
        /// <returns></returns>
        public void ulongAt(long index, ulong value)
        {
            unsafe
            {
                *(ulong*)(((long)_ptr) + index) = value;
            }
        }

        /// <summary>
        /// Returns the UInt64 at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to start copying.</param>
        /// <returns></returns>
        public ulong ulongAt(long index)
        {
            unsafe
            {
                return *(ulong*)(((long)_ptr) + index);
            }
        }

        /// <summary>
        /// Sets the float at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to start copying.</param>
        /// <param name="value">Value to set.</param>
        /// <returns></returns>
        public void floatAt(long index, float value)
        {
            unsafe
            {
                *(float*)(((long)_ptr) + index) = value;
            }
        }

        /// <summary>
        /// Returns the float at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to start copying.</param>
        /// <returns></returns>
        public float floatAt(long index)
        {
            unsafe
            {
                return *(float*)(((long)_ptr) + index);
            }
        }

        /// <summary>
        /// Sets the double at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to start copying.</param>
        /// <param name="value">Value to set.</param>
        /// <returns></returns>
        public void doubleAt(long index, double value)
        {
            unsafe
            {
                *(double*)(((long)_ptr) + index) = value;
            }
        }
        
        /// <summary>
        /// Returns the double at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to start copying.</param>
        /// <returns></returns>
        public double doubleAt(long index)
        {
            unsafe
            {
                return *(double*)(((long)_ptr) + index);
            }
        }
        
        /// <summary>
        /// Sets the decimal at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to start copying.</param>
        /// <param name="value">Value to set.</param>
        /// <returns></returns>
        public void decimalAt(long index, decimal value)
        {
            unsafe
            {
                *(decimal*)(((long)_ptr) + index) = value;
            }
        }

        /// <summary>
        /// Returns the decimal at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to start copying.</param>
        /// <returns></returns>
        public decimal decimalAt(long index)
        {
            unsafe
            {
                return *(decimal*)(((long)_ptr) + index);
            }
        }

        /// <summary>
        /// Sets the System.Guid structure at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to start copying.</param>
        /// <param name="value">Value to set.</param>
        /// <returns></returns>
        public void GuidAt(long index, Guid value)
        {
            unsafe
            {
                *(Guid*)(((long)_ptr) + index) = value;
            }
        }

        /// <summary>
        /// Returns the System.Guid structure at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to start copying.</param>
        /// <returns></returns>
        public Guid GuidAt(long index)
        {
            unsafe
            {
                return *(Guid*)(((long)_ptr) + index);
            }
        }

        #endregion

        #region structures

        /// <summary>
        /// Copies the buffer to a structure of type T.
        /// </summary>
        /// <typeparam name="T">Type of structure to return.</typeparam>
        /// <returns></returns>
        public T ToStruct<T>() where T: struct
        {
            unsafe
            {
                if (_ptr == null) return new T();
                T x = (T)Marshal.PtrToStructure((IntPtr)_ptr, typeof(T));
                return x;
            }

        }

        /// <summary>
        /// Copies the contents of a structure of type T into the buffer.
        /// </summary>
        /// <typeparam name="T">Type of structure to copy.</typeparam>
        /// <param name="value">Structure to copy.</param>
        public void FromStruct<T>(T value) where T: struct
        {
            unsafe
            {
                if (_ptr == null)
                {
                    if(!Alloc(Marshal.SizeOf(new T()))) return;
                }
                Marshal.StructureToPtr(value, (IntPtr)_ptr, false);
            }
        }

        /// <summary>
        /// Gets the specified structure of type T at the specified byte index.
        /// </summary>
        /// <typeparam name="T">Type of structure to copy.</typeparam>
        /// <param name="index">Byte index at which to begin copying.</param>
        /// <returns></returns>
        public T GrabStructAt<T>(long index) where T : struct
        {
            unsafe
            {
                if (_ptr == null) return new T();
                T x = (T)Marshal.PtrToStructure((IntPtr)((void *)((ulong)_ptr + (ulong)index)), typeof(T));
                return x;
            }
        }

        /// <summary>
        /// Sets the specified structure of type T to the specified index.
        /// </summary>
        /// <typeparam name="T">Type of structure to copy.</typeparam>
        /// <param name="index">Byte index at which to begin copying.</param>
        /// <param name="value">Structure to copy.</param>
        public void SetStructAt<T>(long index, T value) where T : struct
        {
            
            unsafe
            {
                if (_ptr == null)
                {
                    if ((index != 0) || (!Alloc(Marshal.SizeOf(new T())))) return;
                }

                Marshal.StructureToPtr(value, (IntPtr)((void*)((ulong)_ptr + (ulong)index)), false);
            }
        }
        
        /// <summary>
        /// Grabs as many blittable structures as possible from the byte index to the end of the buffer.
        /// </summary>
        /// <typeparam name="T">Type of structure to copy.</typeparam>
        /// <param name="index">Byte index at which to begin copying.</param>
        /// <returns></returns>
        public T[] GrabStructArrayAt<T>(long index) where T: struct 
        {
            unsafe
            {
                if (_ptr == null) return null;

                long l = GetLength() - index;

                long cb = Marshal.SizeOf(new T());
                long c = (l / cb);

                T[] ex = new T[c];
                GCHandle h = GCHandle.Alloc(ex, GCHandleType.Pinned);

                void* vp = ((void*)((ulong)_ptr + (ulong)index));
                void* hp = (void*)h.AddrOfPinnedObject();

                Interop.CopyMemory(hp, vp, (IntPtr)l);

                h.Free();
                return ex;
            }
        }

        /// <summary>
        /// Returns an array of blittable structures at the specified index with the specified element count.
        /// </summary>
        /// <typeparam name="T">Type of structure to return.</typeparam>
        /// <param name="index">Byte index at which to begin copying.</param>
        /// <param name="count">Number of elements to copy.</param>
        /// <returns>Array of T.</returns>
        public T[] GrabStructArrayAt<T>(long index, long count) where T : struct
        {
            unsafe
            {
                if (_ptr == null) return null;

                long cb = Marshal.SizeOf(new T());
                long c = count;
                long l = c * cb;

                T[] ex = new T[c];
                GCHandle h = GCHandle.Alloc(ex, GCHandleType.Pinned);

                void* vp = ((void*)((ulong)_ptr + (ulong)index));
                void* hp = (void*)h.AddrOfPinnedObject();

                Interop.CopyMemory(hp, vp, (IntPtr)l);

                h.Free();
                return ex;
            }
        }
        
        /// <summary>
        /// Sets the specified blittable structure array to the specified byte index in the buffer.
        /// </summary>
        /// <typeparam name="T">Type of structure</typeparam>
        /// <param name="index">Byte index to start copying.</param>
        /// <param name="value">Array of T.</param>
        public void SetStructArrayAt<T>(long index, T[] value) where T : struct
        {
            unsafe
            {
                long cb = Marshal.SizeOf(new T());
                long c = value.Length;
                
                long l = c * cb;
                                
                if (_ptr == null)
                {
                    if ((index != 0) || (!Alloc(l))) return;
                }

                GCHandle h = GCHandle.Alloc(value, GCHandleType.Pinned);
               
                void* vp = ((byte*)((ulong)_ptr + (ulong)index));
                void* hv = (void*)h.AddrOfPinnedObject();
               
                Interop.CopyMemory(vp, hv, (IntPtr)(l));
                h.Free();
            }
        }

        /// <summary>
        /// Returns the contents of the memory pointer as an array of T blittable structures.
        /// </summary>
        /// <typeparam name="T">Type structure type to return.</typeparam>
        /// <returns>Array of T.</returns>
        public T[] ToStructArray<T>() where T : struct
        {
            return GrabStructArrayAt<T>(0);
        }

        /// <summary>
        /// Sets the contents of an unmanaged memory pointer to an array of T blittable structures.
        /// </summary>
        /// <typeparam name="T">The type of structure to accept.</typeparam>
        /// <param name="value">The array of values.</param>
        public void FromStructArray<T>(T[] value) where T : struct
        {
            SetStructArrayAt<T>(0, value);
        }

        #endregion

        #region Bytes and Strings

        /// <summary>
        /// Sets the null terminated string at the specified byte index.
        /// If the pointer is null and the index != 0 then nothing happens.
        /// </summary>
        /// <param name="s">String to copy.</param>
        /// <param name="index">Byte index at which to begin copying.</param>
        public void SetString(string s, long index = 0)
        {
            s += (char)0;
            unsafe
            {
                if (_ptr == null)
                {
                    if ((index != 0) || (!Alloc(s.Length * 2))) return;
                }
                Interop.CopyMemory((void*)((long)(_ptr) + index), s, (IntPtr)(s.Length * 2));
            }
        }

        /// <summary>
        /// Returns the null-terminated string at the specified byte index.
        /// </summary>
        /// <param name="index">Index at which to begin copying.</param>
        /// <returns></returns>
        public string GrabString(long index = 0)
        {
            string o;

            unsafe
            {
                if (_ptr == null) return null;
                                
                char* c = (char*)((long)_ptr + index);
                char* orig = c;

                int i = 0;

                while (*c != (char)0)
                {
                    c++;
                    i++;
                }

                o = new string((char)0, i);
                Interop.CopyMemory(o, orig, (IntPtr)(i * 2));
            }

            return o;
        }

        /// <summary>
        /// Grabs a string at the specified byte index with the specified length.
        /// </summary>
        /// <param name="index">Byte index at which to begin copying.</param>
        /// <param name="length">Length, in UTF-16 characters.</param>
        /// <returns></returns>
        public string GrabString(long index, int length)
        {
            string s = new string((char)0, length);
            IntPtr l = (IntPtr)(length * 2);

            unsafe
            {
                if (_ptr == null) return null;

                void* lpsz = (void*)((long)_ptr + index);
                Interop.CopyMemory(s, lpsz, l);
            }

            return s;
        }

        /// <summary>
        /// Returns the contents of the buffer as a string from UTF-8 encoding.
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public string GrabUtf8String(long index = 0)
        {
            byte[] o;

            unsafe
            {
                if (_ptr == null) return null;

                byte* c = (byte*)((long)_ptr + index);
                int i = 0;

                while (*c != (byte)0)
                {
                    c++;
                    i++;
                }

                o = new byte[i];
                Interop.CopyMemory(o, _ptr, (IntPtr)(i * 2));
            }

            return System.Text.Encoding.UTF8.GetString(o);
        }
        
        /// <summary>
        /// Grabs a BSTR-style COM string from the specified byte index.
        /// </summary>
        /// <param name="byteIndex">Index at which to begin copying.</param>
        /// <param name="comptr">Specifies whether this is an actual COM pointer.</param>
        /// <returns></returns>
        public string GrabBSTR(long byteIndex = 0, bool comptr = true)
        {
            unsafe
            {
                void* p = (comptr ? (void*)((ulong)_ptr + (ulong)byteIndex - 4) : (void*)((ulong)_ptr + (ulong)byteIndex));
                int i = 0;
                string s;

                i = *((int*)p);
                s = new string((char)0, i * 2);

                Interop.CopyMemory(s, (void*)((ulong)p + 4), (IntPtr)(i * 2));
                return s;
            }
        }
        
        /// <summary>
        /// Returns the string array at the byteIndex.
        /// </summary>
        /// <param name="byteIndex">Index at which to start copying.</param>
        /// <returns></returns>
        public string[] GrabStringArray(long byteIndex)
        {
            unsafe
            {

                if (_ptr == null) return null;

                string s = null;

                char *cp = (char*)((ulong)_ptr + (ulong)byteIndex);
                char *ap = cp;

                int x = 0;

                List<string> o = new List<string>();

                while (true)
                {

                    if (*ap == (char)0)
                    {
                        if (x != 0)
                        {
                            s = new String((char)0, x);
                            Interop.CopyMemory(s, cp, (IntPtr)(x * 2));
                            o.Add(s);

                            s = null;
                            x = 0;

                            ap++;
                            cp = ap;
                        }
                        else
                        {
                            break;
                        }
                    }
                    else
                    {
                        x++;
                        ap++;
                    }
                }

                return o.ToArray();
            }
           
        }

        /// <summary>
        /// Grabs the specified byte array at the specified index with the specified length.
        /// </summary>
        /// <param name="index">Byte index at which to begin copying.</param>
        /// <param name="length">Number of bytes to copy, or 0 for the entire buffer.</param>
        /// <returns></returns>
        public byte[] GrabBytes(long index = 0, long length = 0)
        {
            byte[] b;

            unsafe
            {
                if (_ptr == null) return null;
                if (length == 0) length = GetLength() - index;

                void* p = (void*)((long)_ptr + index);
                b = new byte[length];
                Interop.CopyMemory(b, p, (IntPtr)length);
            }

            return b;
        }


        /// <summary>
        /// Grabs the specified byte array at the specified index with the specified length.
        /// </summary>
        /// <param name="index">Byte index at which to begin copying.</param>
        /// <param name="length">Number of bytes to copy, or 0 for the entire buffer.</param>
        /// <param name="b">The output buffer that will receive the data.</param>
        public void GrabBytes(long index, long length, ref byte[] b)
        {
            unsafe
            {
                if (_ptr == null) return;
                if (length == 0) length = GetLength() - index;

                void* p = (void*)((long)_ptr + index);
                if (b == null) b = new byte[length];
                Interop.CopyMemory(b, p, (IntPtr)length);
            }
            
        }
       

        /// <summary>
        /// Sets the specified byte array to the specified byte index in the pointer
        /// If the pointer is null, a new memory buffer is allocated.
        /// If the pointer is null but the index is != 0 then nothing happens.
        /// </summary>
        /// <param name="value">The byte array to copy.</param>
        /// <param name="index">The byte index to begin copying.</param>
        public void SetBytes(byte[] value, int index = 0)
        {
            unsafe
            {
                if (_ptr == null)
                {
                    if ((index != 0) || (!Alloc(value.Length))) return;
                }

                Interop.CopyMemory((void*)((long)_ptr + index), value, (IntPtr)value.Length);
            }
        }

        /// <summary>
        /// Returns the contents of the memory pointer as a string.
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return GrabString();
        }

        #endregion

        #region Allocation
        
        /// <summary>
        /// Gets the length of the currently allocated block of memory.
        /// This should only be called by a pointer that you know indicates the beginning of a
        /// block of memory allocated on the process heap.
        /// </summary>
        /// <returns></returns>
        public long GetLength()
        {
            unsafe
            {
                if (_ptr == null) return 0;
                return Interop.HeapSize(Interop.GetProcessHeap(), 0, _ptr).ToInt64();
            }
        }

        /// <summary>
        /// Allocates a block of memory on the process heap.
        /// </summary>
        /// <param name="size">Size of the buffer to allocate.</param>
        /// <param name="addPressure">Specify whether or not to add memory pressure to the garbage collector.</param>
        /// <returns>True if successful.</returns>
        public bool Alloc(long size, bool addPressure = false)
        {
            unsafe
            {
                if (_ptr != null)
                {
                    if (size == GetLength()) return true;
                    return ReAlloc(size);
                }

                void* hheap = Interop.GetProcessHeap();
                _ptr = Interop.HeapAlloc(hheap, 8, new IntPtr(size));
                if (_ptr == null) return false;

                if (addPressure)
                {
                    GC.AddMemoryPressure(size);
                }
                return true;
            }
        }

        /// <summary>
        /// Reallocate a block of memory on the process heap.
        /// </summary>
        /// <param name="size">New size of the memory block.</param>
        /// <param name="changePressure">Specify whether or not to add or remove memory pressure from the garbage collector.</param>
        /// <returns>True if successful.</returns>
        public bool ReAlloc(long size, bool changePressure = false)
        {
            unsafe
            {
                if (_ptr == null) return Alloc(size);

                long l = GetLength();
                
                if (l == size) return true;

                void* hheap = Interop.GetProcessHeap();
                void* n;

                n = Interop.HeapReAlloc(hheap, 8, _ptr, new IntPtr(size));
                if (n == null) return false;

                _ptr = n;

                if (changePressure)
                {
                    if (l > size)
                    {
                        GC.RemoveMemoryPressure(l - size);
                    }
                    else
                    {
                        GC.AddMemoryPressure(size - l);
                    }
                }
                
                return true;
            }
        }

        /// <summary>
        /// Frees a previously allocated block of memory.
        /// </summary>
        /// <param name="removePressure">Specify whether or not to remove memory pressure from the garbage collector.</param>
        /// <returns></returns>
        public bool Free(bool removePressure = false)
        {
            unsafe
            {
                long l = 0;
                if (_ptr == null) return true;

                void* hheap = Interop.GetProcessHeap();

                if (removePressure) l = GetLength();

                if (Interop.HeapFree(hheap, 0, _ptr))
                {
                    if (l != 0) GC.RemoveMemoryPressure(l);
                    _ptr = null;
                    return true;
                }
                return false;
            }
        }

        [DllImport("kernel32.dll", EntryPoint="RtlZeroMemory")]
        private static unsafe extern void RtlZeroMemory(void *buffer, IntPtr length);

        /// <summary>
        /// Sets the contents of a location of memory to zero.
        /// </summary>
        /// <param name="index">Byte index at which to start clearing.</param>
        /// <param name="length">Length of bytes to clear.</param>
        public void ZeroMemory(long index = 0, long length = 0)
        {
            unsafe
            {
                if (_ptr == null) return;
                if (length == 0) length = GetLength();

                void* p = (void *)((ulong)_ptr + (ulong)index);
                RtlZeroMemory(p, (IntPtr)length);
            }
        }

        #endregion Allocation

        #region Aligned Allocation

        /// <summary>
        /// Allocates memory aligned to a particular byte boundary.
        /// Memory allocated in this way must be freed with AlignedFree()
        /// </summary>
        /// <param name="size">Size of the memory to allocate.</param>
        /// <param name="alignment">The byte alignment of the memory.</param>
        /// <param name="addPressure">Specify whether or not to add memory pressure to the garbage collector.</param>
        /// <returns></returns>
        public bool AlignedAlloc(long size, int alignment = 512, bool addPressure = false)
        {
            if(!ispow2(alignment)) //ensure alignment is pow 2
                return false;
 
            unsafe 
            {
                void* pStart, pAligned;

                pStart = Interop.HeapAlloc(Interop.GetProcessHeap(), 8, (IntPtr)(size + (alignment - 1) + 8)); //allocate max memory needed for worst case alignment

                if(pStart == null)
                    return false;
 
                byte *addr = (byte*)pStart + (alignment - 1) + 8;
                pAligned = (void*)(addr - ((long)addr % alignment)); //take max address and subtract the remainder to get aligned pointer
 
                *((long*)pAligned - 1) = (long)pStart; // store start pointer 1 long integer before aligned pointer so we can free the correct pointer later

                _ptr = pAligned;

                if (addPressure)
                {
                    GC.AddMemoryPressure(size + (alignment - 1) + 8);
                }
                return true;
            }
        }

        /// <summary>
        /// Frees a previously allocated block of aligned memory.
        /// </summary>
        /// <param name="removePressure">Specify whether or not to remove memory pressure from the garbage collector.</param>
        /// <returns></returns>
        public bool AlignedFree(bool removePressure = false)
        {
            unsafe
            {
                long l = 0;
                if (_ptr == null)
                    return true;

                void* pTrue = (void*)*((long*)_ptr - 1); // get start pointer from 1 long integer before aligned pointer
                if (removePressure)
                {
                    l = (long)Interop.HeapSize(Interop.GetProcessHeap(), 0, pTrue);
                }

                if (Interop.HeapFree(Interop.GetProcessHeap(), 0, pTrue))
                {
                    GC.RemoveMemoryPressure(l);
                    _ptr = null;
                    return true;
                }
                else
                {
                    return false;
                }
                
            }
        }

        /// <summary>
        /// Checks if memory is aligned to a particular byte alignment.
        /// </summary>
        /// <param name="mem"></param>
        /// <param name="alignment"></param>
        /// <returns></returns>
        private static unsafe bool is_aligned(void* mem, int alignment)
        {
            return ((long)mem) % (alignment) == 0;
        }

        /// <summary>
        /// Checks if a value is a power of two.
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        private static bool ispow2(long value)
        {
            return ((value != 0) && (0 == (value & (value - 1))));  
        }
        
        #endregion Aligned Allocation

        #region Virtual Allocation

        /// <summary>
        /// Allocats a region of virtual memory.
        /// </summary>
        /// <param name="size">The size of the region of memory to allocate.</param>
        /// <param name="addPressure">Whether to call GC.AddMemoryPressure</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public bool VirtualAlloc(long size, bool addPressure = false)
        {
            unsafe {

                if (_ptr != null) return false;

                _ptr = Interop.VirtualAlloc(null, (IntPtr)size,
                                           VMemAllocFlags.MEM_COMMIT |
                                           VMemAllocFlags.MEM_RESERVE,
                                           MemoryProtectionFlags.PAGE_READWRITE);

                bool r = (_ptr != null);

                if (r && addPressure) 
                    GC.AddMemoryPressure(VirtualLength());

                return r;
            }

        }

        /// <summary>
        /// Frees a region of memory previously allocated with VirtualAlloc.
        /// </summary>
        /// <param name="removePressure">Whether to call GC.RemoveMemoryPressure</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public bool VirtualFree(bool removePressure = false)
        {
            unsafe {

                long l = 0;
                if (_ptr == null) return true;

                if (removePressure) l = VirtualLength();

                bool r = Interop.VirtualFree(_ptr, (IntPtr)0);

                if (r)
                {
                    _ptr = null;
                    if (l != 0) GC.RemoveMemoryPressure(l);
                }

                return r;
            }
        }

        /// <summary>
        /// Returns the size of a region of virtual memory previously allocated with VirtualAlloc.
        /// </summary>
        /// <returns>The size of a virtual memory region or zero.</returns>
        /// <remarks></remarks>
        public long VirtualLength()
        {
            unsafe
            {
                if (_ptr == null) return 0;

                MEMORY_BASIC_INFORMATION m = new MEMORY_BASIC_INFORMATION();

                IntPtr r = Interop.VirtualQuery(_ptr, ref m, (IntPtr)Marshal.SizeOf(m));
                if (r != IntPtr.Zero)
                {
                    return (long)m.RegionSize;
                }

                return 0;
            }
        }

        #endregion
        
        #region Instantiation

        /// <summary>
        /// Initialize a new structure with the specified IntPtr as the handle.
        /// </summary>
        /// <param name="ptr">The IntPtr to assign.</param>
        public MemPtr(IntPtr ptr)
        {
            unsafe
            {
                _ptr = ptr.ToPointer();
            }
        }

        /// <summary>
        /// Initialize a new structure with the specified UIntPtr as the handle.
        /// </summary>
        /// <param name="ptr">The UIntPtr to assign.</param>
        public MemPtr(UIntPtr ptr)
        {
            unsafe
            {
                _ptr = ptr.ToPointer();
            }
        }

        /// <summary>
        /// Initialize a new structure with the specified pointer.
        /// </summary>
        /// <param name="ptr">The pointer to assign.</param>
        public unsafe MemPtr(void* ptr)
        {
            _ptr = ptr;
        }

        /// <summary>
        /// Initialize a new structure and allocate a new buffer of the specified size.
        /// </summary>
        /// <param name="size">The size of the new buffer.</param>
        public MemPtr(long size)
        {
            unsafe
            {
                _ptr = null;
            }
            Alloc(size);
        }

        #endregion

        #region Cast Operators

        // strings 

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator string(MemPtr operand)
        {
            return operand.GrabString();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(string operand)
        {
            MemPtr mm = new MemPtr();
            mm.SetString(operand);
            return mm;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator string[](MemPtr operand)
        {
            return operand.GrabStringArray(0);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(string[] operand)
        {
            MemPtr mm = new MemPtr();
            long l = 0;
        
            foreach (string s in operand)
            {
                l += ((s.Length + 1) * 2);
            }
            l += 2;

            mm.Alloc(l);

            unsafe
            {
                void *sp = mm._ptr;

                foreach (string s in operand)
                {
                    l = (s.Length * 2);
                    Interop.CopyMemory(sp, s, (IntPtr)l);
                    sp = (void*)(((ulong)sp) + (ulong)l + 2);
                }

            }

            return mm;
        }

        // pointers

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static unsafe explicit operator void*(MemPtr operand)
        {
            return operand._ptr;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static unsafe explicit operator MemPtr(void* operand)
        {
            return new MemPtr(operand);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator IntPtr(MemPtr operand)
        {
            return operand.Handle;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(IntPtr operand)
        {
            return new MemPtr(operand);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator UIntPtr(MemPtr operand)
        {
            unsafe
            {
                return (UIntPtr)operand._ptr;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(UIntPtr operand)
        {
            return new MemPtr(operand);
        }

        // singletons

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator byte(MemPtr operand)
        {
            unsafe
            {
                if (operand._ptr == null) return 0;
                return *((byte*)operand._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(byte operand)
        {
            unsafe
            {
                MemPtr mm = new MemPtr();
                mm.Alloc(1);
                *((byte*)mm._ptr) = operand;
                return mm;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator sbyte(MemPtr operand)
        {
            unsafe
            {
                if (operand._ptr == null) return 0;
                return *((sbyte*)operand._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(sbyte operand)
        {
            unsafe
            {
                MemPtr mm = new MemPtr();
                mm.Alloc(1);
                *((sbyte*)mm._ptr) = operand;
                return mm;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator char(MemPtr operand)
        {
            unsafe
            {
                if (operand._ptr == null) return (char)0;
                return *((char*)operand._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(char operand)
        {
            unsafe
            {
                MemPtr mm = new MemPtr();
                mm.Alloc(2);
                *((char*)mm._ptr) = operand;
                return mm;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator short(MemPtr operand)
        {
            unsafe
            {
                if (operand._ptr == null) return 0;
                return *((short*)operand._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(short operand)
        {
            unsafe
            {
                MemPtr mm = new MemPtr();
                mm.Alloc(2);
                *((short*)mm._ptr) = operand;
                return mm;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator ushort(MemPtr operand)
        {
            unsafe
            {
                if (operand._ptr == null) return 0;
                return *((ushort*)operand._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(ushort operand)
        {
            unsafe
            {
                MemPtr mm = new MemPtr();
                mm.Alloc(2);
                *((ushort*)mm._ptr) = operand;
                return mm;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator int(MemPtr operand)
        {
            unsafe
            {
                if (operand._ptr == null) return 0;
                return *((int*)operand._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(int operand)
        {
            unsafe
            {
                MemPtr mm = new MemPtr();
                mm.Alloc(4);
                *((int*)mm._ptr) = operand;
                return mm;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator uint(MemPtr operand)
        {
            unsafe
            {
                if (operand._ptr == null) return 0;
                return *((uint*)operand._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(uint operand)
        {
            unsafe
            {
                MemPtr mm = new MemPtr();
                mm.Alloc(4);
                *((uint*)mm._ptr) = operand;
                return mm;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator long(MemPtr operand)
        {
            unsafe
            {
                if (operand._ptr == null) return 0;
                return *((long*)operand._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(long operand)
        {
            unsafe
            {
                MemPtr mm = new MemPtr();
                mm.Alloc(8);
                *((long*)mm._ptr) = operand;
                return mm;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator ulong(MemPtr operand)
        {
            unsafe
            {
                if (operand._ptr == null) return 0;
                return *((ulong*)operand._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(ulong operand)
        {
            unsafe
            {
                MemPtr mm = new MemPtr();
                mm.Alloc(8);
                *((ulong*)mm._ptr) = operand;
                return mm;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator float(MemPtr operand)
        {
            unsafe
            {
                if (operand._ptr == null) return 0;
                return *((float*)operand._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(float operand)
        {
            unsafe
            {
                MemPtr mm = new MemPtr();
                mm.Alloc(4);
                *((float*)mm._ptr) = operand;
                return mm;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator double(MemPtr operand)
        {
            unsafe
            {
                if (operand._ptr == null) return 0;
                return *((double*)operand._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(double operand)
        {
            unsafe
            {
                MemPtr mm = new MemPtr();
                mm.Alloc(8);
                *((double*)mm._ptr) = operand;
                return mm;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator decimal(MemPtr operand)
        {
            unsafe
            {
                if (operand._ptr == null) return 0;
                return *((decimal*)operand._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(decimal operand)
        {
            unsafe
            {
                MemPtr mm = new MemPtr();
                mm.Alloc(16);
                *((decimal*)mm._ptr) = operand;
                return mm;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator Guid(MemPtr operand)
        {
            unsafe
            {
                if (operand._ptr == null) return Guid.Empty;
                return *((Guid*)operand._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(Guid operand)
        {
            unsafe
            {
                MemPtr mm = new MemPtr();
                mm.Alloc(16);
                *((Guid*)mm._ptr) = operand;
                return mm;
            }
        }

        // buffers

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator byte[](MemPtr operand)
        {
            unsafe
            {
                if (operand._ptr == null) return null;
                byte[] o = new byte[operand.GetLength()];
                Interop.CopyMemory(o, operand._ptr, (IntPtr)o.Length);
                return o;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(byte[] operand)
        {
            unsafe
            {
                MemPtr mm = new MemPtr();
                mm.Alloc(operand.Length);
                Interop.CopyMemory(mm._ptr, operand, (IntPtr)operand.Length);
                return mm;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator sbyte[](MemPtr operand)
        {
            unsafe
            {
                if (operand._ptr == null) return null;
                sbyte[] o = new sbyte[operand.GetLength()];
                Interop.CopyMemory(o, operand._ptr, (IntPtr)o.Length);
                return o;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(sbyte[] operand)
        {
            unsafe
            {
                MemPtr mm = new MemPtr();
                mm.Alloc(operand.Length);
                Interop.CopyMemory(mm._ptr, operand, (IntPtr)operand.Length);
                return mm;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator short[](MemPtr operand)
        {
            unsafe
            {
                if (operand._ptr == null) return null;
                long l = operand.GetLength();
                if ((l % 2) != 0) return null;

                short[] o = new short[l / 2];
                Interop.CopyMemory(o, operand._ptr, (IntPtr)l);
                return o;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(short[] operand)
        {
            unsafe
            {
                MemPtr mm = new MemPtr();
                long l = operand.Length * 2;
                mm.Alloc(l);
                Interop.CopyMemory(mm._ptr, operand, (IntPtr)l);
                return mm;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator ushort[](MemPtr operand)
        {
            unsafe
            {
                if (operand._ptr == null) return null;
                long l = operand.GetLength();
                if ((l % 2) != 0) return null;

                ushort[] o = new ushort[l / 2];
                Interop.CopyMemory(o, operand._ptr, (IntPtr)l);
                return o;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(ushort[] operand)
        {
            unsafe
            {
                MemPtr mm = new MemPtr();
                long l = operand.Length * 2;
                mm.Alloc(l);
                Interop.CopyMemory(mm._ptr, operand, (IntPtr)l);
                return mm;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator char[](MemPtr operand)
        {
            unsafe
            {
                if (operand._ptr == null) return null;
                long l = operand.GetLength();
                if ((l % 2) != 0) return null;

                char[] o = new char[l / 2];
                Interop.CopyMemory(o, operand._ptr, (IntPtr)l);
                return o;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(char[] operand)
        {
            unsafe
            {
                MemPtr mm = new MemPtr();
                long l = operand.Length * 2;
                mm.Alloc(l);
                Interop.CopyMemory(mm._ptr, operand, (IntPtr)l);
                return mm;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator int[](MemPtr operand)
        {
            unsafe
            {
                if (operand._ptr == null) return null;
                long l = operand.GetLength();
                if ((l % 4) != 0) return null;

                int[] o = new int[l / 4];
                Interop.CopyMemory(o, operand._ptr, (IntPtr)l);
                return o;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(int[] operand)
        {
            unsafe
            {
                MemPtr mm = new MemPtr();
                long l = operand.Length * 4;
                mm.Alloc(l);
                Interop.CopyMemory(mm._ptr, operand, (IntPtr)l);
                return mm;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator uint[](MemPtr operand)
        {
            unsafe
            {
                if (operand._ptr == null) return null;
                long l = operand.GetLength();
                if ((l % 4) != 0) return null;

                uint[] o = new uint[l / 4];
                Interop.CopyMemory(o, operand._ptr, (IntPtr)l);
                return o;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(uint[] operand)
        {
            unsafe
            {
                MemPtr mm = new MemPtr();
                long l = operand.Length * 4;
                mm.Alloc(l);
                Interop.CopyMemory(mm._ptr, operand, (IntPtr)l);
                return mm;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator long[](MemPtr operand)
        {
            unsafe
            {
                if (operand._ptr == null) return null;
                long l = operand.GetLength();
                if ((l % 8) != 0) return null;

                long[] o = new long[l / 8];
                Interop.CopyMemory(o, operand._ptr, (IntPtr)l);
                return o;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(long[] operand)
        {
            unsafe
            {
                MemPtr mm = new MemPtr();
                long l = operand.Length * 8;
                mm.Alloc(l);
                Interop.CopyMemory(mm._ptr, operand, (IntPtr)l);
                return mm;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator ulong[](MemPtr operand)
        {
            unsafe
            {
                if (operand._ptr == null) return null;
                long l = operand.GetLength();
                if ((l % 8) != 0) return null;

                ulong[] o = new ulong[l / 8];
                Interop.CopyMemory(o, operand._ptr, (IntPtr)l);
                return o;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(ulong[] operand)
        {
            unsafe
            {
                MemPtr mm = new MemPtr();
                long l = operand.Length * 8;
                mm.Alloc(l);
                Interop.CopyMemory(mm._ptr, operand, (IntPtr)l);
                return mm;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator float[](MemPtr operand)
        {
            unsafe
            {
                if (operand._ptr == null) return null;
                long l = operand.GetLength();
                if ((l % 4) != 0) return null;

                float[] o = new float[l / 4];
                Interop.CopyMemory(o, operand._ptr, (IntPtr)l);
                return o;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(float[] operand)
        {
            unsafe
            {
                MemPtr mm = new MemPtr();
                long l = operand.Length * 4;
                mm.Alloc(l);
                Interop.CopyMemory(mm._ptr, operand, (IntPtr)l);
                return mm;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator double[](MemPtr operand)
        {
            unsafe
            {
                if (operand._ptr == null) return null;
                long l = operand.GetLength();
                if ((l % 8) != 0) return null;

                double[] o = new double[l / 8];
                Interop.CopyMemory(o, operand._ptr, (IntPtr)l);
                return o;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(double[] operand)
        {
            unsafe
            {
                MemPtr mm = new MemPtr();
                long l = operand.Length * 8;
                mm.Alloc(l);
                Interop.CopyMemory(mm._ptr, operand, (IntPtr)l);
                return mm;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator decimal[](MemPtr operand)
        {
            unsafe
            {
                if (operand._ptr == null) return null;
                long l = operand.GetLength();
                if ((l % 16) != 0) return null;

                decimal[] o = new decimal[l / 16];
                Interop.CopyMemory(o, operand._ptr, (IntPtr)l);
                return o;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(decimal[] operand)
        {
            unsafe
            {
                MemPtr mm = new MemPtr();
                long l = operand.Length * 16;
                mm.Alloc(l);
                Interop.CopyMemory(mm._ptr, operand, (IntPtr)l);
                return mm;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator Guid[](MemPtr operand)
        {
            unsafe
            {
                if (operand._ptr == null) return null;
                long l = operand.GetLength();
                if ((l % 16) != 0) return null;

                Guid[] o = new Guid[l / 16];
                Interop.CopyMemory(o, operand._ptr, (IntPtr)l);
                return o;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand"></param>
        /// <returns></returns>
        public static implicit operator MemPtr(Guid[] operand)
        {
            unsafe
            {
                MemPtr mm = new MemPtr();
                long l = operand.Length * 16;
                mm.Alloc(l);
                Interop.CopyMemory(mm._ptr, operand, (IntPtr)l);
                return mm;
            }
        }

        #endregion

        #region Comparison Operators

        /// <summary>
        /// Tests whether or not this structure is equal to the specified object.
        /// </summary>
        /// <param name="obj">Object to compare.</param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            if (obj.GetType() == typeof(MemPtr))
            {
                unsafe
                {
                    return (((MemPtr)obj)._ptr == _ptr);
                }
            }
            else if (obj.GetType() == typeof(IntPtr))
            {
                unsafe
                {
                    return (((IntPtr)obj).ToPointer() == _ptr);
                }
            }
            else if (obj.GetType() == typeof(UIntPtr))
            {
                unsafe
                {
                    return (((UIntPtr)obj).ToPointer() == _ptr);
                }
            }
            return false;
        }

        /// <summary>
        /// Returns the hashcode of this structure.
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            unsafe
            {
                int x = (int)(long)(_ptr);
                return (x >> 4) ^ -1;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator ==(MemPtr operand1, MemPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 == (void*)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator ==(IntPtr operand1, MemPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 == (void*)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator ==(MemPtr operand1, IntPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 == (void*)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator ==(UIntPtr operand1, MemPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 == (void*)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator ==(MemPtr operand1, UIntPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 == (void*)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator !=(MemPtr operand1, MemPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 != (void*)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator !=(IntPtr operand1, MemPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 != (void*)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator !=(MemPtr operand1, IntPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 != (void*)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator !=(UIntPtr operand1, MemPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 != (void*)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator !=(MemPtr operand1, UIntPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 != (void*)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator >(MemPtr operand1, MemPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 > (void*)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator >(IntPtr operand1, MemPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 > (void*)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator >(MemPtr operand1, IntPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 > (void*)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator >(UIntPtr operand1, MemPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 > (void*)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator >(MemPtr operand1, UIntPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 > (void*)operand2);
            }
        }
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator <(MemPtr operand1, MemPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 < (void*)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator <(IntPtr operand1, MemPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 < (void*)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator <(MemPtr operand1, IntPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 < (void*)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator <(UIntPtr operand1, MemPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 < (void*)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator <(MemPtr operand1, UIntPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 < (void*)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator >=(MemPtr operand1, MemPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 >= (void*)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator >=(IntPtr operand1, MemPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 >= (void*)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator >=(MemPtr operand1, IntPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 >= (void*)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator >=(UIntPtr operand1, MemPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 >= (void*)operand2);
            }
        }
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator >=(MemPtr operand1, UIntPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 >= (void*)operand2);
            }
        }
                
        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator <=(MemPtr operand1, MemPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 <= (void*)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator <=(IntPtr operand1, MemPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 <= (void*)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator <=(MemPtr operand1, IntPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 <= (void*)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator <=(UIntPtr operand1, MemPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 <= (void*)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static bool operator <=(MemPtr operand1, UIntPtr operand2)
        {
            unsafe
            {
                return ((void*)operand1 <= (void*)operand2);
            }
        }
        
        #endregion

        #region Pointer Arithmatic

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator +(MemPtr operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr + (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator -(MemPtr operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr - (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator *(MemPtr operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr * (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator /(MemPtr operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr / (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator %(MemPtr operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr % (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator +(MemPtr operand1, short operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr + (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator +(MemPtr operand1, ushort operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr + (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator +(short operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 + (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator +(ushort operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 + (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator -(MemPtr operand1, short operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr - (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator -(MemPtr operand1, ushort operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr - (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator -(short operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 - (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator -(ushort operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 - (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator *(MemPtr operand1, short operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr * (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator *(MemPtr operand1, ushort operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr * (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator *(short operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 * (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator *(ushort operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 * (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator /(MemPtr operand1, short operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr / (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator /(MemPtr operand1, ushort operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr / (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator /(short operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 / (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator /(ushort operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 / (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator %(MemPtr operand1, short operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr % (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator %(MemPtr operand1, ushort operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr % (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator %(short operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 % (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator %(ushort operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 % (ulong)operand2._ptr);
            }
        }
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator +(MemPtr operand1, int operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr + (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator +(MemPtr operand1, uint operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr + (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator +(int operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 + (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator +(uint operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 + (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator -(MemPtr operand1, int operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr - (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator -(MemPtr operand1, uint operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr - (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator -(int operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 - (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator -(uint operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 - (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator *(MemPtr operand1, int operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr * (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator *(MemPtr operand1, uint operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr * (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator *(int operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 * (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator *(uint operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 * (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator /(MemPtr operand1, int operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr / (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator /(MemPtr operand1, uint operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr / (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator /(int operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 / (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator /(uint operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 / (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator %(MemPtr operand1, int operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr % (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator %(MemPtr operand1, uint operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr % (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator %(int operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 % (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator %(uint operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 % (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator +(MemPtr operand1, long operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr + (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator +(MemPtr operand1, ulong operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr + (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator +(long operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 + (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator +(ulong operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 + (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator -(MemPtr operand1, long operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr - (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator -(MemPtr operand1, ulong operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr - (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator -(long operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 - (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator -(ulong operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 - (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator *(MemPtr operand1, long operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr * (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator *(MemPtr operand1, ulong operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr * (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator *(long operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 * (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator *(ulong operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 * (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator /(MemPtr operand1, long operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr / (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator /(MemPtr operand1, ulong operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr / (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator /(long operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 / (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator /(ulong operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 / (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator %(MemPtr operand1, long operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr % (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator %(MemPtr operand1, ulong operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1._ptr % (ulong)operand2);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator %(long operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 % (ulong)operand2._ptr);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="operand1"></param>
        /// <param name="operand2"></param>
        /// <returns></returns>
        public static MemPtr operator %(ulong operand1, MemPtr operand2)
        {
            unsafe
            {
                return (MemPtr)(void*)((ulong)operand1 % (ulong)operand2._ptr);
            }
        }

        #endregion

    }

}